﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Windows.Navigation;
using System.Globalization;
using Microsoft.Phone.Shell;

namespace CarBloke.Pages
{
    public partial class LogEditPage : PhoneApplicationPage
    {
        bool _saveState = true;
        string costFormat = "f";

        const String _descriptionKey = "LogEditPageDescription";
        const String _odometerKey = "LogEditPageOdometer";
        const String _quantityKey = "LogEditPageFuelQuantity";
        const String _costKey = "LogEditPageCost";
        const String _notesKey = "LogEditPageNotes";
        const String _fullTankKey = "LogEditPageFullTank";
        const String _misseLogsKey = "LogEditPageMissedLogs";
        const String _dateKey = "LogEditPageDate";

        ApplicationBarIconButton deleteButton = null;
        private LogEntry _logEntry = null;
        private DateTime? dateTime = null;

        private Boolean initialValidation = false;

        public LogEditPage()
        {
            InitializeComponent();

            //Application bar and application menu text must be set here explicitly.
            var saveButton = ApplicationBar.Buttons[0] as ApplicationBarIconButton;
            var cancelButton = ApplicationBar.Buttons[1] as ApplicationBarIconButton;
            saveButton.Text = LanguageResources.Resources._save;
            cancelButton.Text = LanguageResources.Resources._cancel;
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);

            if (_saveState)
                saveState();
            else
                clearState();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            string vehicleID = "";
            Double? odometer = null;
            Double? fuelQuantity = null;
            Double? cost = null;

            if (NavigationContext.QueryString.TryGetValue("vehicleID", out vehicleID))
            {
                Vehicle vehicle = App.LoadVehicle(new Guid(vehicleID));
                VehicleName.Text = vehicle.Name;

                String logID = null;
                String logType = null;

                if (NavigationContext.QueryString.TryGetValue("logID", out logID))
                {
                    _logEntry = App.LoadLogEntry(new Guid(vehicleID), new Guid(logID));

                    odometer = UnitConversions.Convert(_logEntry.OdometerReading, ApplicationSettings.DistanceUnits.Kilometers, ApplicationSettings.Current.DistanceUnit);
                    fuelQuantity = UnitConversions.Convert(_logEntry.FuelAdded, ApplicationSettings.VolumeUnits.Liter, ApplicationSettings.Current.VolumeUnit);

                    if (_logEntry.LogType == LogEntry.LogTypes.Fuel && !Double.IsNaN(_logEntry.Cost))
                    {
                        cost = _logEntry.Cost / fuelQuantity;
                        costFormat = "f3";
                    }
                    else if (!Double.IsNaN(_logEntry.Cost))
                    {
                        cost = _logEntry.Cost;
                        costFormat = "f";
                    }

                    //Add a new application button for delete
                    if (deleteButton == null)
                    {
                        deleteButton = new ApplicationBarIconButton();
                        deleteButton.Text = LanguageResources.Resources._delete;
                        deleteButton.IconUri = new Uri("/Images/AppBar/delete.png", UriKind.Relative);
                        deleteButton.Click += new EventHandler(appbar_deleteButton_Click);
                        ApplicationBar.Buttons.Add(deleteButton);
                    }
                }
                else if (NavigationContext.QueryString.TryGetValue("logType", out logType))
                {
                    LogEntry.LogTypes type = (LogEntry.LogTypes)Enum.Parse(typeof(LogEntry.LogTypes), logType, true);
                    _logEntry = new LogEntry()
                    {
                        ID = Guid.NewGuid(),
                        LogType = type,
                        LogTime = DateTime.Now,
                        VehicleID = new Guid(vehicleID),
                        FullTank = true,
                    };
                }
            }

            initalizeInterfaceToLogType();

            //odometer
            if (odometer != null)
                odometerTextBox.Text = odometer.Value.ToString("f", CultureInfo.CurrentCulture);
            else
                odometerTextBox.Text = "";

            //fuel quantity
            if (fuelQuantity != null)
                fuelQuantityTextBox.Text = fuelQuantity.Value.ToString("f3", CultureInfo.CurrentCulture);
            else
                fuelQuantityTextBox.Text = "";

            //cost
            if (cost != null && !Double.IsNaN(cost.Value))
                costTextBox.Text = cost.Value.ToString(costFormat, CultureInfo.CurrentCulture);
            else
                costTextBox.Text = "";

            descriptionTextBox.Text = _logEntry.Description ?? "";
            fullCheckBox.IsChecked = _logEntry.FullTank;
            missedLogsCheckBox.IsChecked = _logEntry.MissedLogs;

            notesTextBox.Text = _logEntry.Notes ?? "";

            restoreState();

            if (dateTime != null)
            {
                dateTextBox.Value = dateTime;
                dateTime = null;
            }
            else
            {
                dateTextBox.Value = _logEntry.LogTime; 
            }
        }

        private void appbar_deleteButton_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show(LanguageResources.Resources.DeleteLogWarning, LanguageResources.Resources.DeleteLogTitle, MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                _saveState = false;
                App.DeleteLogEntry(_logEntry);
                NavigationService.GoBack();
            }
        }

        private void initalizeInterfaceToLogType()
        {
            dateTextBlock.Text = LanguageResources.Resources._date + " (" + CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern + ")";

            switch (_logEntry.LogType)
            {
                case LogEntry.LogTypes.Fuel:
                    descriptionTextBlock.Visibility = Visibility.Collapsed;
                    descriptionTextBox.Visibility = Visibility.Collapsed;
                    PageTitle.Text = LanguageResources.Resources._fuel;
                    odometerTextBlock.Text = LanguageResources.Resources._odometer +" (" + ApplicationSettings.ToLongString(ApplicationSettings.Current.DistanceUnit, true) + ")";
                    fuelQuantityTextBlock.Text = LanguageResources.Resources._fuel + " (" + ApplicationSettings.ToLongString(ApplicationSettings.Current.VolumeUnit, true) + ")";
                    costTextBlock.Text = LanguageResources.Resources._cost + " (" + CultureInfo.CurrentCulture.NumberFormat.CurrencySymbol + " / " + ApplicationSettings.ToShortString(ApplicationSettings.Current.VolumeUnit) + ")";                    
                    break;
                case LogEntry.LogTypes.Oil:
                    fuelQuantityGrid.Visibility = Visibility.Collapsed;
                    fuelQuantityTextBlock.Visibility = Visibility.Collapsed;
                    fuelQuantityTextBox.Visibility = Visibility.Collapsed;
                    fullCheckBox.Visibility = Visibility.Collapsed;
                    descriptionTextBlock.Visibility = Visibility.Collapsed;
                    descriptionTextBox.Visibility = Visibility.Collapsed;
                    PageTitle.Text = LanguageResources.Resources._oil;
                    break;
                case LogEntry.LogTypes.Other:
                    fuelQuantityGrid.Visibility = Visibility.Collapsed;
                    fuelQuantityTextBlock.Visibility = Visibility.Collapsed;
                    fuelQuantityTextBox.Visibility = Visibility.Collapsed;
                    fullCheckBox.Visibility = Visibility.Collapsed;
                    PageTitle.Text = LanguageResources.Resources._maintenance;
                    break;
            }
        }

        private void appbar_saveButton_Click(object sender, EventArgs e)
        {
            Boolean passedValidation = performValidation();

            if (!passedValidation)
                return;

            _saveState = false;

            //Description
            _logEntry.Description = descriptionTextBox.Text;

            //Odometer
            Double distance = Double.Parse(odometerTextBox.Text, CultureInfo.CurrentCulture);
            _logEntry.OdometerReading = UnitConversions.Convert(distance, ApplicationSettings.Current.DistanceUnit, ApplicationSettings.DistanceUnits.Kilometers);
            
            //Fuel
            if (_logEntry.LogType == LogEntry.LogTypes.Fuel)
            {
                //Fuel Quantity
                Double fuelQuantity = Double.Parse(fuelQuantityTextBox.Text, CultureInfo.CurrentCulture);
                _logEntry.FuelAdded = UnitConversions.Convert(fuelQuantity, ApplicationSettings.Current.VolumeUnit, ApplicationSettings.VolumeUnits.Liter);

                //Full tank
                _logEntry.FullTank = fullCheckBox.IsChecked.Value;

                //Missed logs
                _logEntry.MissedLogs = missedLogsCheckBox.IsChecked.Value;
            }

            //Cost
            _logEntry.Cost = double.NaN;
            if (!String.IsNullOrEmpty(costTextBox.Text))
            {
                if (_logEntry.LogType == LogEntry.LogTypes.Fuel)
                {
                    Double fuelQuantity = Double.Parse(fuelQuantityTextBox.Text, CultureInfo.CurrentCulture);
                    _logEntry.Cost = Double.Parse(costTextBox.Text, CultureInfo.CurrentCulture) * fuelQuantity;
                }
                else
                {
                    _logEntry.Cost = Double.Parse(costTextBox.Text, CultureInfo.CurrentCulture);
                }
            }

            //Date
            if (dateTextBox.Value != null)
                _logEntry.LogTime = dateTextBox.Value.Value;
            else
                _logEntry.LogTime = DateTime.Now;

            //Notes
            _logEntry.Notes = notesTextBox.Text;

            //Save and go back
            App.SaveLogEntry(_logEntry);
            NavigationService.GoBack();
        }

        private void appbar_cancelButton_Click(object sender, EventArgs e)
        {
            _saveState = false;
            NavigationService.GoBack();
        }

        protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
        {
            _saveState = false;
            base.OnBackKeyPress(e);
        }

        private void dateTextBox_ValueChanged(object sender, DateTimeValueChangedEventArgs e)
        {
            clearState(_dateKey);
            dateTime = e.NewDateTime;
        }

        private bool performValidation()
        {
            initialValidation = true;

            Boolean passedValidation = true;
            passedValidation &= validateOdometer();
            passedValidation &= validateFuelQuantity();
            passedValidation &= validateDescription();
            passedValidation &= validateCost();
            return passedValidation;
        }

        private bool validateOdometer()
        {
            Boolean passedValidation = true;
            clearWarning(odometerBorder);

            //Validation 1, odomoter is required, and needs to be an int, and needs to be positive
            if (String.IsNullOrEmpty(odometerTextBox.Text))
            {
                setError(odometerBorder);
                passedValidation = false;
            }
            else
            {
                double testValue;
                if (!double.TryParse(odometerTextBox.Text, out testValue))
                {
                    setError(odometerBorder);
                    passedValidation = false;
                }
                else if (testValue < 0)
                {
                    setError(odometerBorder);
                    passedValidation = false;
                }
            }

            return passedValidation;
        }

        private bool validateFuelQuantity()
        {
            Boolean passedValidation = true;
            clearWarning(fuelQuantityBorder);

            //Validation 2, fuel quantity is required for fuel log, and needs to be a double, and needs to be positive
            if (_logEntry.LogType == LogEntry.LogTypes.Fuel)
            {
                if (String.IsNullOrEmpty(fuelQuantityTextBox.Text))
                {
                    setError(fuelQuantityBorder);
                    passedValidation = false;
                }
                else
                {
                    double testValue;
                    if (!double.TryParse(fuelQuantityTextBox.Text, out testValue))
                    {
                        setError(fuelQuantityBorder);
                        passedValidation = false;
                    }
                    else if (testValue <= 0)
                    {
                        setError(fuelQuantityBorder);
                        passedValidation = false;
                    }
                }
            }
            return passedValidation;
        }

        private bool validateDescription()
        {
            Boolean passedValidation = true;
            clearWarning(descriptionBorder);

            //Validation 3 description is requried for other logs
            if (_logEntry.LogType == LogEntry.LogTypes.Other)
            {
                if (String.IsNullOrEmpty(descriptionTextBox.Text))
                {
                    setError(descriptionBorder);
                    passedValidation = false;
                }
            }

            return passedValidation;
        }

        private bool validateCost()
        {
            Boolean passedValidation = true;
            clearWarning(costBorder);

            if (!String.IsNullOrEmpty(costTextBox.Text))
            {
                double testValue;
                if (!double.TryParse(costTextBox.Text, out testValue))
                {
                    setError(costBorder);
                    passedValidation = false;
                }
                else if (testValue < 0)
                {
                    setError(costBorder);
                    passedValidation = false;
                }
            }

            return passedValidation;
        }


        private void setError(Border border)
        {
            Color errorColor = Colors.Red;
            errorColor.A = 0xAA;

            border.Background = new SolidColorBrush(errorColor);
        }

        private void clearWarning(Border border)
        {
            border.Background = null;
        }

        private void descriptionTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (initialValidation)
            {
                validateDescription();
            }
        }

        private void odometerTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (initialValidation)
            {
                validateOdometer();
            }
        }

        private void fuelQuantityTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (initialValidation)
            {
                validateFuelQuantity();
            }
        }

        private void costTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (initialValidation)
            {
                validateCost();
            }
        }

        private void fuelQuantityTextBlock_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            fuelQuantityTextBox.Focus();
            e.Handled = true;
        }

        private void descriptionTextBlock_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            descriptionTextBox.Focus();
            e.Handled = true;
        }

        private void odometerTextBlock_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            odometerTextBox.Focus();
            e.Handled = true;
        }

        private void costTextBlock_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            costTextBox.Focus();
            e.Handled = true;
        }

        private void notesTextBlock_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            notesTextBox.Focus();
            e.Handled = true;
        }

        private void dateTextBlock_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            dateTextBox.Focus();
            e.Handled = true;
        }


        private void saveState()
        {
            saveState(_descriptionKey, descriptionTextBox);
            saveState(_odometerKey, odometerTextBox);
            saveState(_quantityKey, fuelQuantityTextBox);
            saveState(_costKey, costTextBox);
            saveState(_notesKey, notesTextBox);
            saveState(_fullTankKey, fullCheckBox);
            saveState(_misseLogsKey, missedLogsCheckBox);
            saveState(_dateKey, dateTextBox);
        }

        private void saveState(String key, TextBox textbox)
        {
            clearState(key);
            PhoneApplicationService.Current.State.Add(key, textbox.Text);
        }

        private void saveState(String key, CheckBox checkBox)
        {
            clearState(key);
            PhoneApplicationService.Current.State.Add(key, checkBox.IsChecked);
        }

        private void saveState(String key, DatePicker datePicker)
        {
            clearState(key);
            PhoneApplicationService.Current.State.Add(key, datePicker.Value);
        }    

        private void restoreState()
        {
            restoreState(_descriptionKey, descriptionTextBox);
            restoreState(_odometerKey, odometerTextBox);
            restoreState(_quantityKey, fuelQuantityTextBox);
            restoreState(_costKey, costTextBox);
            restoreState(_notesKey, notesTextBox);
            restoreState(_fullTankKey, fullCheckBox);
            restoreState(_misseLogsKey, missedLogsCheckBox);
            restoreState(_dateKey, dateTextBox);
        }

        private void restoreState(String key, TextBox textbox)
        {
            if (true == PhoneApplicationService.Current.State.ContainsKey(key))
            {
                string s = PhoneApplicationService.Current.State[key] as string;
                if (!String.IsNullOrEmpty(s))
                {
                    textbox.Text = s;
                }
            }
        }

        private void restoreState(String key, CheckBox checkBox)
        {
            if (true == PhoneApplicationService.Current.State.ContainsKey(key))
            {
                bool? b = PhoneApplicationService.Current.State[key] as bool?;
                checkBox.IsChecked = b;
            }
        }

        private void restoreState(String key, DatePicker datePicker)
        {
            if (true == PhoneApplicationService.Current.State.ContainsKey(key))
            {
                DateTime? dt = PhoneApplicationService.Current.State[key] as DateTime?;
                datePicker.Value = dt;
            }
        }

        private void clearState()
        {
            clearState(_descriptionKey);
            clearState(_odometerKey);
            clearState(_quantityKey);
            clearState(_costKey);
            clearState(_notesKey);
            clearState(_fullTankKey);
            clearState(_misseLogsKey);
            clearState(_dateKey);
        }

        private void clearState(string key)
        {
            if (true == PhoneApplicationService.Current.State.ContainsKey(key))
            {
                PhoneApplicationService.Current.State.Remove(key);
            }
        }










        private void squirt()
        {
            Random rand = new Random();
            DateTime fuelStartTime = new DateTime(2010, 2, 12);
            double fuelOdometerStart = 51412;

            //Fuel Logs (100)
            for (int i = 0; i < 25; i++)
            {
                fuelStartTime = fuelStartTime.AddDays(rand.Next(7, 14));

                LogEntry entry = new LogEntry();
                entry.VehicleID = _logEntry.VehicleID;
                entry.LogType = LogEntry.LogTypes.Fuel;
                entry.LogTime = fuelStartTime;
                entry.ID = Guid.NewGuid();


                double kml = rand.NextDouble() * 3 + 10;

                double km = rand.NextDouble() * 80 + 317;
                fuelOdometerStart = fuelOdometerStart + km;
                entry.FuelAdded = km / kml;
                entry.OdometerReading = fuelOdometerStart;

                entry.Cost = (rand.NextDouble() + 1.8) * entry.FuelAdded * 0.264172052;

                if (rand.NextDouble() > .9)
                {
                    entry.FullTank = false;
                }
                else
                {
                    entry.FullTank = true;
                }

                if (rand.NextDouble() > .97)
                {
                    entry.MissedLogs = true;
                }
                else
                {
                    entry.MissedLogs = false;
                }

                App.SaveLogEntry(entry);
            }
        }

    }
}